package main

import (
	"fmt"
	"time"
)

func main() {

	// TestForRangeString()
	// TestForRangeWithGoroutine()
	// TestForContinueAndBreakWithLabel()
	// TestRangeArray()
	TestRangeMap()
}

// 使用 label 快速跳出多层循环
func TestForContinueAndBreakWithLabel() {
	var sl = [][]int{
		{1, 34, 26, 35, 78},
		{3, 45, 13, 24, 99},
		{101, 13, 38, 7, 127},
		{54, 27, 40, 83, 81},
	}

	fmt.Printf("test continue label: \n")
outerloop1:
	for i, l := 0, len(sl); i < l; i++ {
		for j := 0; j < len(sl[i]); j++ {
			if sl[i][j] == 13 {
				fmt.Printf("found 13 at [%d, %d]!\n", i, j)
				continue outerloop1
			}
			fmt.Printf("[%d, %d] miss...\n", i, j)
		}
	}

	fmt.Printf("test break label: \n")
outerloop2:
	for i, l := 0, len(sl); i < l; i++ {
		for j := 0; j < len(sl[i]); j++ {
			if sl[i][j] == 13 {
				fmt.Printf("found 13 at [%d, %d]!\n", i, j)
				break outerloop2
			}
			fmt.Printf("[%d, %d] miss...\n", i, j)
		}
	}
}

// for range string 是 rune 而非 byte
func TestForRangeString() {

	s := "hello, Go语言"
	for _, c := range s {
		fmt.Printf("%s: 0x%x\n", string(c), c)
	}
}

// for 中使用 goroutine 需要用闭包，避免运行时得到非预期的值
func TestForRangeWithGoroutine() {

	arr := []int{1, 2, 3, 4, 5}
	/*
		fmt.Printf("without closure\n")
		for i, n := range arr {
			go func() {
				time.Sleep(time.Second * 1)
				fmt.Printf("%d: %d\n", i, n)
			}()
		}
		time.Sleep(time.Second * 3)
	*/

	fmt.Printf("with closure\n")
	for i, n := range arr {
		go func(i int, n int) {
			time.Sleep(time.Second * 1)
			fmt.Printf("%d: %d\n", i, n)
		}(i, n)
	}
	time.Sleep(time.Second * 3)
}

// range 数组 时使用的是 数组的拷贝
func TestRangeArray() {

	arr := [5]int{1, 2, 3, 4, 5}
	var arr2 [5]int
	fmt.Printf("range with array:\n")
	for i, n := range arr {
		if i == 0 {
			arr[1] = 22
			arr[2] = 33
		}
		arr2[i] = n
	}
	fmt.Printf("arr %#v\n", arr)
	fmt.Printf("arr2 %#v\n", arr2)

	fmt.Printf("range with slice:\n")
	for i, n := range arr[:] {
		if i == 0 {
			arr[1] = 22
			arr[2] = 33
		}
		arr2[i] = n
	}
	fmt.Printf("arr %#v\n", arr)
	fmt.Printf("arr2 %#v\n", arr2)
}

// map 循环是修改了键值对，新增/删除的键值对可能参与循环，也可能不参与，即 每次运行可能结果不一样
func TestRangeMap() {

	ages := map[string]int{
		"xiaoming": 12,
		"xiaohong": 10,
		"xiaohua":  11,
	}

	for k, v := range ages {
		if k == "xiaohong" {
			ages["xiaogang"] = 11
			delete(ages, "xiaohua")
		}
		fmt.Printf("%s => %d\n", k, v)
	}
}
